#ifndef JOUEUR_H
#define JOUEUR_H

#include "Classe.h"

#include "debugstreams.h"

#include "StatusCode.h"

#include <vector>
#include <map>

using namespace std;

/**
 * @addtogroup Utilitaires
 * @{
 */

/**
 * Sert à énumérer les différents types de classes multiples.
 */
enum TypeMulti  {
  Non, /**< Le Joueur n'a qu'une classe */
  Mul, /**< Le Joueur est multiclassé */
  Jum /**< Le Joueur a jumelé */
};

/**
 * Enumère les Dons / Désavantages
 */
enum TypeComp  {Don, Desav};

/**
 * \}
 */

class Race;
class Classe;
class Parser;
class ElementDOM;

/**
 * Cette classe permet la création de la feuille de perso. Un Joueur
 * possède une Race, une (ou plusieurs) Classe. Depuis Joueur il est
 * possible décire un fichier XML, d'en lire et finalement de produire
 * le code LaTeX qui fera une jolie feuille de personnage. Le Joueur
 * est en fait l'implémentation du PJ.
 *
 * @todo Pourquoi ne pas mettre les traits dans Joueur plutôt que dans
 * Race ? Le problème serait que beaucoup de méthodes de Classe on
 * besoin des traits pour fonctionner, mais ce n'est pas optimal pour
 * les multiclassés...
 *
 * @author Johan "Solo" Luisier
 */
class Joueur
{
 public:
  Joueur();
  Joueur(Classe* classe, Race* race, const string& nom);
  Joueur( map< string, string >* infoXML );
  Joueur( Parser const* parser );
  ~Joueur();
  /****************************************************************************
   *
   * Méthodes
   *
   ***************************************************************************/
  void information(ostream& os = blank());
  string demanderNom() const;
  void ecrireXml() const;
  void setPP(const unsigned int& pps, const bool& creation = false);
  void setPV(const unsigned int& pv);
  void setDons(const vector<unsigned int>& vec);
  void setDesavantages(const vector<unsigned int>& vec);
  void setDiverses(const vector<unsigned int>& vec);
  void setMartiales(const vector<unsigned int>& vec);
  void setAcces(const vector<unsigned int>& vec);
  void ajouterDiverses(const vector<unsigned int>& aAjouter);
  void ajouterMartiales(const vector<unsigned int>& aAjouter);
  void initDiverses(const vector<unsigned int>& vec);

  void ajoutClasse(Classe* classe);
  void ecrireTex(const bool& UI = false) const;
  unsigned int getCombienDons() const;
  unsigned int getCombienDesavantages() const;
  unsigned int getCombienCompetences() const;
  unsigned int getCombienCompMartiales() const;
  string getNom() const;
  string getRace() const;
  const Race* getRacePtr() const;
  unsigned int getNbrClasse() const;
  Classe* getClassePtr(const unsigned int& i = 99) const;
  void getTraits(unsigned int tab[7]) const;
  string getCapaRaciale() const;
  unsigned int getTypeMulti() const;
  unsigned int getNbrPV() const;
  unsigned int getNbrPP() const;
  string getAjustementPV() const;
  const vector<TypeClasse>* getAcces(unsigned int& nbr) const;
  const vector<Sort>* getSorts(unsigned int& nbr, const unsigned int& i = 0) const;
  const vector<unsigned int>* getDons(unsigned int& nbr) const;
  const vector<unsigned int>* getDesavantages(unsigned int& nbr) const;
  const vector<unsigned int>* getDiverses(unsigned int& nbr) const;
  const vector<unsigned int>* getMartiales(unsigned int& nbr) const;
  unsigned int getListeDons(vector<ListCapa> &vec) const;
  unsigned int getListeDesavantages(vector<ListCapa> &vec) const;
  const string* getListeCategories(unsigned int& nbr) const;
  const ListNonMart* getListeCompetences(unsigned int& nbr) const;
  const ListNonMart getCompDsListe(const unsigned int& i) const;
  const vector<unsigned int>* getMartialeClasse(const string& nomClasse)
    const;
  unsigned int getNiveauMagie() const;
  static void setLevel(const unsigned int& level, const unsigned int& n);
  string aSortsMage(vector<Classe *>& vec) const;
  string convertNom() const;

  /****************************************************************************
   *
   * Fonctions de gestion de l'évolution du Joueur
   *
   ***************************************************************************/

  void determinerDonsDesavantages(const TypeComp& quoi);
  void determinerCompetences();
  void augmenterCompetences();
  void determinerCompMartiales();
  StatusCode ajouterXP(const unsigned int& xp);
  void ajouterPP(const unsigned int& pp);
  void ajouterPV(const unsigned int& pv);

 protected:
  /**
   * Nom du personnage
   */
  string Nom;
  /**
   * Contient la (les) classe(s) du personnage
   * @see Classe
   */
  vector< Classe* > J_classe;
  /**
   * Contient la race du personnage
   * @see Race
   */
  Race* J_race;
  unsigned int TAc0, /**< TAC0 du personnage */
    PV, /**< Nombre de pts de vie */
    PP, /**< Nombre de pp restant */
    nb_classes; /**< Nombre de classes (dimension de J_classe) */
  /**
   * Classe d'armure
   */
  int CA;
  vector<unsigned int> J_CompDiv, /**< Compétences diverses */
    J_Dons, /**< Dons */
    J_Desavantages, /**< Désavantages */
    J_Martiales; /**< Compétences martiales */
  /**
   * Compétences diverses accessibles (Roublard, Combattant, etc...)
   */
  vector<TypeClasse> J_CompAccess;
 
  /****************************************************************************
   *
   * Niveaux de sortie des sous-fonctions
   * 'static', toujours par soucis d'optimisation
   *
   ***************************************************************************/

  /**
   * Niveau de sortie basique pour la gestion du XML.
   */
  static DebugLevelType fonction_elementaire_xml;
  /**
   * Niveau de sortie pour les fonctions de récupération d'information
   * à partir du XML.
   */
  static DebugLevelType fonction_recuperation_xml;
  /**
   * Niveau de sortie des fonctions écrivant les sources .tex.
   */
  static DebugLevelType fonction_tex;
  /**
   * Niveau de sortie pour les autres fonctions.
   */
  static DebugLevelType interne;

  /**
   * Permet de déterminer si les niveaux de sorties ont bien été
   * initialisés.
   */
  static bool niveauxLus;
  /**
   * Liste des noms des niveaux de sorties paramétrables.
   */
  static const vector< string > NomsNiveaux;

 private:
  /****************************************************************************
   *
   * Ajustements dus aux traits, sont stockés sous forme de tableaux 'static'
   * par soucis d'optimisation.
   *
   ***************************************************************************/

  /**
   * Ajustements au toucher, aux dégâts, charge autorisée, charge
   * maximale, défoncer portes, barreaux & herses.
   */
  static const string Aj_Force[30][6];
  /**
   * Ajustement réflexe, ajustement aux missiles, ajustement défensif.
   */
  static const string Aj_Dexterite[14][3];
  /**
   * Ajustement au PV, choc métabolique, régénération, survie à la
   * résurection, ajustement aux JS contre les Poisons.
   */
  static const string Aj_Const[25][5];
  /**
   * Nombre de langues, niveau de sort maximal, pourcentage
   * d'apprentissage de sorts, nombre maximal de sort par niveau,
   * immunité aux illusions.
   */
  static const string Aj_Int[19][5];
  /**
   * Bonus aux JS contre les sorts mentaux, sorts bonus, pourcentage
   * d'échec des sorts, immunité aux sorts.
   */
  static const string Aj_Sagesse[24][4];
  /**
   * Nombre de compagnon d'arme, loyauté inspirée, bonus à la
   * réaction.
   */
  static const string Aj_Charisme[24][3];

  /****************************************************************************
   *
   * Dons, désavantages et compétences non-martiales
   * 'static', toujours par soucis d'optimisation
   *
   ***************************************************************************/

  static const vector< ListCapa > Dons, /**< Liste des dons @see ListCapa */
    Desavantages; /**< Liste des désavantages @see ListCapa */

  /**
   * Liste des compétences diverses.
   * @see ListNonMart
   */
  static const ListNonMart CompetencesDiverses[85];

  /**
   * Liste des catégories de compétences diverses (Générale,
   * Combattant, ...).
   */
  static const string CategoriesCompetences[5];

  /**
   * Liste des compétences martiales disponibles pour chaque classe
   * 'static', toujours par soucis d'optimisation.\n
   *
   * Pour chaque classe on garde la position dans
   * CompMartialesParClasse de sa liste d'armes.
   */
  static const map<string, unsigned int> GererClasses;

  /**
   * Ce tableau contient des pointeurs vers les listes d'armes
   * disponibles pour chaque type de classe.\n
   *
   * Les combattants ont accès à toutes les armes, alors on ne déclare
   * pas de variables pour eux, et CompMartialesParClasse contient 0
   * pour ces classes.\n
   *
   * On utilise une astuce, si deux classes ont la même liste d'arme,
   * il n'existe qu'une seule liste, mais on va ici stocker deux
   * poitneurs différents.
   */
  static const vector<unsigned int>* CompMartialesParClasse[5];

  /*
   * Mages et Spécialistes on la même sélection d'armes => un seul
   * tableau mais deux pointeurs dans CompMartialesParClasse.
   */
  static const vector<unsigned int>
    CompMarMage, /**< Liste des armes accessbibes aux Mages et Spécialistes */
    CompMarClerc, /**< Liste d'armes accessibles aux Prêtres */
    CompMarDruide, /**< Liste d'armes accessibles aux Druides */
    CompMarVoleur;/**< Liste d'armes accessibles aux Voleurs */

  /**
   * Gestion de la mémoire allouée dynamiquement.
   */
  bool libere_mem;
  /**
   * Gestion de multiclassé ou classes jumelées (=> gestion des XPs).
   * @see TypeMulti
   */
  TypeMulti TM_switch;
  void modificateurPP();
  void modificateurVal(unsigned int& val, const unsigned int& trait);
  void nettoieTC();
  void gererDiverses(const vector<unsigned int>& numeros,
		      vector<unsigned int>& comp);

  /****************************************************************************
   *
   * Sous-fonctions qui écrivent les différentes parties du code .tex
   * nécessaire pour la feuille complète.
   *
   ***************************************************************************/

  void ecrireTraitsTex() const;
  void ecrireJSTex() const;
  void ecrireScoresTex() const;
  void ecrireRaceTex() const;
  void ecrireClasseTex() const;
  void ecrireCompTex() const;
  void ecrireSortsTex() const;

  void construitJoueur( map< string, string >* infoXML );

  StatusCode verifieBalise(const ElementDOM* elDom, const string& bal) const;
  void faireVerificationBalise(const ElementDOM* elDom, const string& bal) const;
  void lireClasse(const ElementDOM* elDom, const string& prefixe,
		  const Parser* parser, map< string, string >& infos) const;
  /*
    void lireEtStockerDonnees(const ElementDOM* elDom, const string& bal
    map< string, string >& infos) const;
  */
};

#endif
